function init(obj) xr_motivator.AddToMotivator(obj) end function actor_init(npc) npc:bind_object(actor_binder(npc)) end ---------------------------------------------------------------------------------------------------------------------- class "actor_binder" (object_binder) ---------------------------------------------------------------------------------------------------------------------- function actor_binder:__init (obj) super(obj) db.actor_binder = self --utils_data.debug_write("actor init start") self.bCheckStart = false --self.last_level_name = "nil" -- Not used for anything self.deimos_intensity = nil sound_theme.load_sound() self.last_detective_achievement_spawn_time = nil self.last_mutant_hunter_achievement_spawn_time = nil bind_stalker_ext.actor_on_init(self) --utils_data.debug_write("actor init end") end ---------------------------------------------------------------------------------------------------------------------- function actor_binder:net_spawn(se_abstract) --utils_data.debug_write("actor net spawn start") if object_binder.net_spawn(self,se_abstract) == false then return false end level.show_indicators() self.bCheckStart = true self.weapon_hide = false self.talking_state = false self.weapon_lowered_before_dialog = false db.add_actor(self.object) db.add_enemy(self.object) level_weathers.get_weather_manager():reset() db.actor.deimos_intensity = self.deimos_intensity self.deimos_intensity = nil if self.st.disable_input_time == nil then level.enable_input() end death_manager.init_drop_settings() self.spawn_frame = device().frame self.already_jumped = false self.loaded = false bind_stalker_ext.actor_on_net_spawn(self) --utils_data.debug_write("actor net spawn end") return true end ---------------------------------------------------------------------------------------------------------------------- function actor_binder:net_destroy() --utils_data.debug_write("actor net destroy start") local sm = surge_manager.get_surge_manager() if (sm) then sm:finalize() end sm = psi_storm_manager.get_psi_storm_manager() if (sm) then sm:finalize() end sm = level_weathers.get_weather_manager() if (sm) then sm:finalize() end xr_sound.stop_sounds_by_id(self.object:id()) if (USE_MARSHAL) then UnregisterScriptCallback("save_state",self) end bind_stalker_ext.actor_on_net_destroy(self) level.show_weapon(true) db.del_actor(self.object) db.delete_enemy(self.object) -- remove callbacks local t = { -- vanilla callback.inventory_info, callback.on_item_take, callback.on_item_drop, callback.task_state, callback.trade_sell_buy_item, callback.take_item_from_box, callback.use_object, -- coc callback.hud_animation_end, callback.hit, callback.key_press, callback.key_release, callback.key_hold, callback.actor_before_death, callback.on_attach_vehicle, callback.on_detach_vehicle, callback.on_use_vehicle, callback.weapon_fired, callback.weapon_jammed, callback.weapon_zoom_in, callback.weapon_zoom_out, callback.weapon_magazine_empty, callback.weapon_lowered, callback.weapon_raised, callback.weapon_no_ammo, callback.item_to_slot, callback.item_to_belt, callback.item_to_ruck, callback.on_foot_step } for i=1,#t do if (t[i]) then self.object:set_callback(t[i]) end end if(_G.amb_vol~=0) then exec_console_cmd("snd_volume_eff "..tostring(_G.amb_vol)) _G.amb_vol = 0 end if(_G.mus_vol~=0) then exec_console_cmd("snd_volume_music "..tostring(_G.mus_vol)) _G.mus_vol = 0 end if sr_psy_antenna.psy_antenna then sr_psy_antenna.psy_antenna:destroy() sr_psy_antenna.psy_antenna = false end object_binder.net_destroy(self) --utils_data.debug_write("actor net destroy end") end ---------------------------------------------------------------------------------------------------------------------- function actor_binder:reinit() object_binder.reinit(self) --utils_data.debug_write("actor reinit start") local npc_id = self.object:id() db.storage[npc_id] = empty_table(db.storage[npc_id]) self.st = db.storage[npc_id] local t = { -- vanilla ["inventory_info"] = bind_stalker_ext.actor_on_info_callback, ["on_item_take"] = bind_stalker_ext.actor_on_item_take, ["on_item_drop"] = bind_stalker_ext.actor_on_item_drop, ["task_state"] = bind_stalker_ext.actor_on_task_callback, ["trade_sell_buy_item"] = bind_stalker_ext.actor_on_trade, ["take_item_from_box"] = bind_stalker_ext.actor_on_item_take_from_box, ["use_object"] = bind_stalker_ext.actor_on_item_use, -- coc ["hud_animation_end"] = bind_stalker_ext.actor_on_hud_animation_end, ["hit"] = bind_stalker_ext.actor_on_hit_callback, ["key_press"] = bind_stalker_ext.on_key_press, ["key_release"] = bind_stalker_ext.on_key_release, ["key_hold"] = bind_stalker_ext.on_key_hold, ["actor_before_death"] = bind_stalker_ext.actor_on_before_death, ["on_attach_vehicle"] = bind_stalker_ext.actor_on_attach_vehicle, ["on_detach_vehicle"] = bind_stalker_ext.actor_on_detach_vehicle, ["on_use_vehicle"] = bind_stalker_ext.actor_on_use_vehicle, ["weapon_fired"] = bind_stalker_ext.actor_on_weapon_fired, ["weapon_jammed"] = bind_stalker_ext.actor_on_weapon_jammed, ["weapon_zoom_in"] = bind_stalker_ext.actor_on_weapon_zoom_in, ["weapon_zoom_out"] = bind_stalker_ext.actor_on_weapon_zoom_out, ["weapon_magazine_empty"] = bind_stalker_ext.actor_on_weapon_magazine_empty, ["weapon_lowered"] = bind_stalker_ext.actor_on_weapon_lowered, ["weapon_raised"] = bind_stalker_ext.actor_on_weapon_raised, ["weapon_no_ammo"] = bind_stalker_ext.actor_on_weapon_reload, -- note: in engine this actually called on try_reload. ["item_to_belt"] = bind_stalker_ext.actor_item_to_belt, ["item_to_slot"] = bind_stalker_ext.actor_item_to_slot, ["item_to_ruck"] = bind_stalker_ext.actor_item_to_ruck, ["on_foot_step"] = bind_stalker_ext.actor_on_foot_step } for cb,func in pairs(t) do if (callback[cb] and func) then self.object:set_callback(callback[cb],func,self) end end if (USE_MARSHAL) then RegisterScriptCallback("save_state",self) end bind_stalker_ext.actor_on_reinit(self) alife():set_objects_per_update(65534) -- To force all of alife to spawn and update at least once --utils_data.debug_write("actor reinit end") end ---------------------------------------------------------------------------------------------------------------------- function actor_binder:update(delta) object_binder.update(self, delta) --utils_data.debug_write("actor update START") if not (db.actor:alive()) then return end if self.bCheckStart then -- first update after netspawn self.bCheckStart = nil --utils_data.debug_write("actor first_update START") bind_stalker_ext.actor_on_first_update(self,delta) if not has_alife_info("global_dialogs") then self.object:give_info_portion("global_dialogs") end if not has_alife_info("level_changer_icons") then self.object:give_info_portion("level_changer_icons") end pda.fill_primary_objects() self.object:activate_slot(self.loaded_active_slot or 0) db.actor.afterFirstUpdate = true if (self.character_icon) then db.actor:set_character_icon(self.character_icon) end local function set_obj_per_upd() alife():set_objects_per_update(20) return true end CreateTimeEvent(0,"obj_per_upd",1,set_obj_per_upd) printf("collectgarbage before=%sKb",collectgarbage("count")*1024) collectgarbage("collect") collectgarbage("collect") printf("collectgarbage after=%sKb",collectgarbage("count")*1024) --utils_data.debug_write("actor first_update END") end task_manager.get_task_manager():update() level_weathers.get_weather_manager():update() xr_sound.update(self.object:id()) itms_manager.get_item_processor():update() -- Обновление отключения ввода с клавиатуры. if (self.st.disable_input_time ~= nil and game.get_game_time():diffSec(self.st.disable_input_time) >= self.st.disable_input_idle) then level.enable_input() self.st.disable_input_time = nil end -- Апдейт прятание оружия игрока во время диалога if self.object:is_talking() then if self.talking_state == false then local wpn = db.actor:active_item() if (wpn) then local can_be_lowered = wpn and IsWeapon(wpn) and ini_sys:r_bool_ex(wpn:section(), "can_be_lowered", false) or false local state = wpn:get_state() if (can_be_lowered and not(state == 0 or state == 1)) then can_be_lowered = false end if (can_be_lowered) then if (not game.actor_weapon_lowered()) then game.actor_lower_weapon(true) weapon_lowered_before_dialog = false else weapon_lowered_before_dialog = true end else self.object:hide_weapon() self.weapon_hide = true end end self.talking_state = true end else if self.talking_state == true then if (self.weapon_hide) then self.weapon_hide = false self.object:restore_weapon() end if ((not weapon_lowered_before_dialog) and game.actor_weapon_lowered()) then game.actor_lower_weapon(false) weapon_lowered_before_dialog = false end self.talking_state = false end end -- обновление пси-антенны if sr_psy_antenna.psy_antenna then sr_psy_antenna.psy_antenna:update(delta) end trans_outfit.timer_trans() -- уменьшение дистанции видимости при одевании соотв. броников -- Апдейт доступности для симуляции. --simulation_objects.get_sim_obj_registry():update_avaliability(alife():actor()) bind_stalker_ext.actor_on_update(self,delta) --utils_data.debug_write("actor update END 2") end ---------------------------------------------------------------------------------------------------------------------- function actor_binder:save(packet) set_save_marker(packet, "save", false, "actor_binder") object_binder.save(self, packet) set_save_marker(packet, "save", true, "actor_binder") if (USE_MARSHAL) then if (level_changing()) then save_var(db.actor,"heli_enemy_flag",nil) SendScriptCallback("on_level_changing") end return end --utils_data.debug_write("--------------- actor_binder:save -------- Start") set_save_marker(packet, "save", false, "actor_binder") if (level_changing()) then save_var(db.actor,"heli_enemy_flag",nil) end --alundaio utils_data.w_stpk(packet,"u8",level.get_game_difficulty(), "game difficulty") utils_data.w_stpk(packet,"CTime",self.st.disable_input_time, "disable input time") xr_logic.pstor_save_all(self.object, packet) sr_psy_antenna.save( packet ) utils_data.w_stpk(packet,"bool",SIMBOARD.simulation_started, "sim started") xr_sound.actor_save(packet) --utils_data.w_stpk(packet,"stringZ",self.last_level_name,"last level name") game_statistics.save(packet) task_manager.get_task_manager():save(packet) packet:w_u8(self.object:active_slot()) utils_data.w_stpk(packet,"CTime",self.last_detective_achievement_spawn_time, "detective spawn time") utils_data.w_stpk(packet,"CTime",self.last_mutant_hunter_achievement_spawn_time, "hunter spawn time") bind_stalker_ext.actor_on_save(self,packet) --utils_data.debug_write("--------------- actor_binder:save -------- End") end function actor_binder:load(reader) set_save_marker(reader, "load", false, "actor_binder") object_binder.load(self, reader) set_save_marker(reader, "load", true, "actor_binder") if (USE_MARSHAL) then self:load_state(alife_storage_manager.get_state()) -- fake because binder not ready when load_state callback is really made bind_stalker_ext.actor_on_load(self,reader) return end --utils_data.debug_write("actor_binder:load start") local game_difficulty_by_num = { [0] = "gd_novice", [1] = "gd_stalker", [2] = "gd_veteran", [3] = "gd_master" } local dif = game_difficulty_by_num[reader:r_u8()] if not (dif) then abort("actor_binder:load save corrupted!") return end exec_console_cmd("g_game_difficulty "..dif) self.st.disable_input_time = utils_data.r_CTime(reader,"bind_stalker") xr_logic.pstor_load_all(self.object, reader) sr_psy_antenna.load(reader) SIMBOARD.simulation_started = reader:r_bool() xr_sound.actor_load(reader) --[[ local n = reader:r_stringZ() if(n~="nil") then self.last_level_name = n end --]] game_statistics.load(reader) task_manager.get_task_manager():load(reader) self.loaded_active_slot = reader:r_u8() local stored_achievement_time = reader:r_bool() if stored_achievement_time == true then self.last_detective_achievement_spawn_time = utils_data.r_CTime(reader,"bind_stalker") end stored_achievement_time = reader:r_bool() if stored_achievement_time == true then self.last_mutant_hunter_achievement_spawn_time = utils_data.r_CTime(reader,"bind_stalker") end --utils_data.debug_write("actor_binder:load end") end ---------------------------------------------------------------------------------------------------------------------- function actor_binder:save_state(m_data) --utils_data.debug_write(strformat("actor_binder:save_state BEFORE")) local state = alife_storage_manager.get_game_object_state(self.object,true) if not (state.actor_binder) then state.actor_binder = {} end state.actor_binder.game_difficulty = level.get_game_difficulty() state.actor_binder.disable_input_time = self.st.disable_input_time state.actor_binder.simulation_started = SIMBOARD.simulation_started --state.actor_binder.last_level_name = self.last_level_name state.actor_binder.active_slot = self.object:active_slot() state.actor_binder.last_detective_achievement_spawn_time = self.last_detective_achievement_spawn_time state.actor_binder.last_mutant_hunter_achievement_spawn_time = self.last_mutant_hunter_achievement_spawn_time state.actor_binder.character_icon = self.character_icon if (sr_psy_antenna.psy_antenna and sr_psy_antenna.psy_antenna.global_state ~= 0 and not level_changing()) then sr_psy_antenna.psy_antenna:save_state(m_data) end game_statistics.save_state(m_data) inventory_upgrades.save_state(m_data) xr_sound.actor_save_state(state) task_manager.save_state(m_data) level_weathers.get_weather_manager():save_state(m_data) surge_manager.save_state(m_data) psi_storm_manager.save_state(m_data) db.storage[0].pstor = db.storage[0].pstor or {} --utils_data.debug_write(strformat("actor_binder:save_state AFTER")) end function actor_binder:load_state(m_data) local state = alife_storage_manager.get_game_object_state(self.object) if not (state and state.actor_binder) then return end --utils_data.debug_write("actor_binder:load_state before") local game_difficulty_by_num = { [0] = "gd_novice", [1] = "gd_stalker", [2] = "gd_veteran", [3] = "gd_master" } exec_console_cmd("g_game_difficulty "..game_difficulty_by_num[state.actor_binder.game_difficulty or 3]) self.st.disable_input_time = state.actor_binder.disable_input_time SIMBOARD.simulation_started = state.actor_binder.simulation_started --self.last_level_name = state.actor_binder.last_level_name self.loaded_active_slot = state.actor_binder.active_slot or 0 self.last_detective_achievement_spawn_time = state.actor_binder.last_detective_achievement_spawn_time self.last_mutant_hunter_achievement_spawn_time = state.actor_binder.last_mutant_hunter_achievement_spawn_time self.character_icon = state.actor_binder.character_icon if (sr_psy_antenna.psy_antenna) then sr_psy_antenna.psy_antenna:load_state(m_data) end game_statistics.load_state(m_data) inventory_upgrades.load_state(m_data) xr_sound.actor_load_state(state) task_manager.load_state(m_data) level_weathers.get_weather_manager():load_state(m_data) surge_manager.load_state(m_data) psi_storm_manager.load_state(m_data) if (state.pstor_all) then db.storage[0].pstor = state.pstor_all state.pstor_all = nil end if (state.pstor_ctime) then db.storage[0].pstor_ctime = state.pstor_ctime state.pstor_ctime = nil end state.actor_binder = nil --utils_data.debug_write("actor_binder:load_state after") end